//------------------------------------------------------------------------------
// <copyright company="Telligent Systems">
//     Copyright (c) Telligent Systems Corporation.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------

using System.Web;
using System.Web.Caching;
using CommunityServer.Components;


namespace CommunityServer.Components
{
	/// <summary>
	/// The base class for all syndication (RSS, Atom, etc.) handlers.
	/// </summary>
	public abstract class BaseSyndicationHandler : System.Web.IHttpHandler
	{
		/// <summary>
		/// The blog/Forum we're serving up this feed for.
		/// </summary>
		protected Section CurrentSection = null;

		/// <summary>
		/// The HTTP context that we're replying to.
		/// </summary>
		protected HttpContext Context = null;

		/// <summary>
		/// The feed itself.
		/// </summary>
		protected CachedFeed Feed = null;

		/// <summary>
		/// The If-Modified-Since header of the request.
		/// </summary>
		protected string IfModifiedSinceHeader
		{
			get
			{
				return Context.Request.Headers["If-Modified-Since"] as string;
			}
		}

		/// <summary>
		/// The If-None-Match header of the request.
		/// </summary>
		protected string IfNoneMatchHeader
		{
			get
			{
				return Context.Request.Headers["If-None-Match"] as string;
			}
		}

		/// <summary>
		/// Is this feed suitable for storing in the cache?
		/// </summary>
		protected virtual bool FeedIsCacheable
		{
			get { return true; }
		}

		/// <summary>
		/// The length of time the feed should be cached in seconds.
		/// </summary>
		protected virtual int CacheTime { get {return 30;} }

		/// <summary>
		/// The key used to lookup the feed uniquely in the cache.
		/// </summary>
		/// <returns></returns>
		protected abstract string CacheKey { get; }

        /// <summary>
        /// The Fully Qualifed part of the Url for the current request
        /// </summary>
        protected abstract string BaseUrl{ get; }

		/// <summary>
		/// Write a 304 Not Modified response to the request.
		/// </summary>
		private void WriteNotModifiedResponse()
		{
			Context.Response.StatusCode = 304;
			Context.Response.Status = "304 Not Modified";
		}

		/// <summary>
		/// Builds the actual feed.
		/// </summary>
		/// <returns>The cached feed.</returns>
		protected abstract CachedFeed BuildFeed();

		/// <summary>
		/// Write the feed.
		/// </summary>
		protected virtual void WriteFeed()
		{
			Context.Response.ContentEncoding = System.Text.Encoding.UTF8;
			Context.Response.ContentType = "text/xml";
			Context.Response.Cache.SetCacheability(HttpCacheability.Public);
			Context.Response.Cache.SetLastModified(Feed.LastModified);
			Context.Response.Cache.SetETag(Feed.Etag);
			Context.Response.Write(Feed.Xml);
		}

        protected virtual CacheItemPriority Priority
        {
            get {return CacheItemPriority.Normal;}
        }

		/// <summary>
		/// Figure out what the response to the request is.
		/// </summary>
		protected virtual void ProcessFeed()
		{


			// First, load up the feed. Note that we CANNOT use the blog's LastUpdated
			// property for anything in here because it may not accurately reflect
			// the state of even the default feed. LastUpdated is changed whenever an
			// entry OR an article is added OR updated, so it may not be in sync with
			// the create time for the last entry.
			if (FeedIsCacheable)
			{
				Feed = Context.Cache[this.CacheKey] as CachedFeed;
			}

			if (Feed == null)
			{
                
				if ((Feed = BuildFeed()) == null)
				{
					return;
				}

				if (FeedIsCacheable)
				{
                    CSCache.Insert(CacheKey,Feed,CSCache.SecondFactorCalculate(CacheTime),Priority);
				}
			}

			// Now check if the conditional nature of the GET indicates we can just
			// return a 304.
			if (Feed.IsCacheOK(IfNoneMatchHeader, IfModifiedSinceHeader))
			{
				WriteNotModifiedResponse();
			}
			else
			{
				WriteFeed();
			}
		}

		/// <summary>
		/// Process the request for the feed.
		/// </summary>
		/// <param name="context">The HTTP context for the request.</param>
		public virtual void ProcessRequest(HttpContext context)
		{
            CSContext csContext = CSContext.Current;
            if(csContext.IsUserTokenRequest && !csContext.SiteSettings.EnableSecureSyndication)
            {
                Globals.Return404(context);
                return;
            }
			
			Context = context;
		    CurrentSection = GetCurrentSection;
			ProcessFeed();
		}

        protected  abstract Section GetCurrentSection
        {
            get;
        }

		/// <summary>
		/// Is this HTTP handler reusable?
		/// </summary>
		public virtual bool IsReusable
		{
			get { return false; }
		}
	}
}
